﻿// License: The MIT License (MIT) Copyright (c) 2012 Barend Gehrels

// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Windows;
using System.Windows.Controls;
using Stormy;

namespace GrooveSharp
{
    public partial class ConfigurationFlags : UserControl
    {
        private const string ADDED_FLAG = "<to be entered>";


        private class FlagInfo : DependencyObject
        {
            #region PROPERTY REGISTRATION
            public static readonly DependencyProperty
                IdProperty = DependencyProperty.Register("Id",
                    typeof(int?), typeof(FlagInfo),
                        new UIPropertyMetadata(null));

            public static readonly DependencyProperty
                FlagNameProperty = DependencyProperty.Register("FlagName",
                    typeof(string), typeof(FlagInfo),
                        new UIPropertyMetadata(null));

            public static readonly DependencyProperty
                ActiveProperty = DependencyProperty.Register("Active",
                    typeof(bool?), typeof(FlagInfo),
                        new UIPropertyMetadata(null));

            #endregion

            private ConfigurationFlags m_editor;

            public FlagInfo(ConfigurationFlags editor)
            {
                m_editor = editor;
            }

            public int Id
            {
                get { return (int)GetValue(IdProperty); }
                set { SetValue(IdProperty, value); }
            }

            public string FlagName
            {
                get { return (string)GetValue(FlagNameProperty); }
                set { SetValue(FlagNameProperty, value); }
            }

            public bool? Active
            {
                get { return (bool?)GetValue(ActiveProperty); }
                set { SetValue(ActiveProperty, value); }
            }

            public int Count { get; set; }

            protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
            {
                m_editor.m_commitNecessary = true;
                //m_editor.textBlockDebug.Text = "True after Property Changed";
            }
        }

        private class FlagInfoMapper : ISelectable<FlagInfo>, IInsertable<FlagInfo>, IUpdateable<FlagInfo>, IAutoNumberable<FlagInfo>, IDeleteable<FlagInfo>
        {
            private ConfigurationFlags m_config;

            public FlagInfoMapper(ConfigurationFlags editor)
            {
                m_config = editor;
            }

            public FlagInfo ApplySelect(IDataReader reader)
            {
                int count = reader.AsInteger("count").Value;
                return new FlagInfo(m_config)
                {
                    Id = reader.AsInteger("track_flag_id", 0),
                    FlagName = reader.AsString("track_flag_name"),
                    Active = reader.AsBool("is_active"),
                    Count = count
                };
            }

            public string UpdateSql()
            {
                return "update track_flags set track_flag_name=@flag,is_active=@active where track_flag_id=@id";
            }

            public string InsertSql()
            {
                return "insert into track_flags(track_flag_name,is_active) values(@flag,@active)";
            }

            public string DeleteSql()
            {
                return "delete from track_flags where track_flag_id=@id";
            }


            private void Add_Flag_And_Active(FlagInfo item, IDbCommand command)
            {
                command.Parameters.Add(Db.CreateParameter(command, DbType.String, "@flag", item.FlagName));
                command.Parameters.Add(Db.CreateParameter(command, DbType.Boolean, "@active", item.Active));
            }
            private void Add_Id(FlagInfo item, IDbCommand command)
            {
                command.Parameters.Add(Db.CreateParameter(command, DbType.Int32, "@id", item.Id));
            }

            public void ApplyInsert(FlagInfo item, IDbCommand command)
            {
                Add_Flag_And_Active(item, command);
            }

            public void ApplyUpdate(FlagInfo item, IDbCommand command)
            {
                Add_Id(item, command);
                Add_Flag_And_Active(item, command);
            }

            public void ApplyAutoNumber(FlagInfo item, int newId)
            {
                item.Id = newId;
            }

            public void ApplyDelete(FlagInfo item, IDbCommand command)
            {
                Add_Id(item, command);
            }

        }


        private ObservableCollection<FlagInfo> m_items;
        private ObservableCollection<FlagInfo> m_deletedItems = new ObservableCollection<FlagInfo>();
        private bool m_commitNecessary = false;


        public ConfigurationFlags()
        {
            InitializeComponent();

            Orm.Register<FlagInfo>(new FlagInfoMapper(this));

            if (!DesignerProperties.GetIsInDesignMode(this))
            {
                Refresh();
            }
        }

        public void Refresh()
        {
            theListView.ItemsSource = null;

            m_items = new ObservableCollection<FlagInfo>
                (
                    Db.Connection().Select<FlagInfo>("select f.*,(select count(1) from link_track_flag k where f.track_flag_id=k.track_flag_id) as count from track_flags f")
                );

            theListView.ItemsSource = m_items;
            m_items.CollectionChanged += delegate(object o, NotifyCollectionChangedEventArgs e)
            {
                m_commitNecessary = true;
                //textBlockDebug.Text = "True after Collection Changed";

            };
            m_commitNecessary = false;
            //textBlockDebug.Text = "False after Refresh";
        }

        private void buttonAdd_Click(object sender, RoutedEventArgs e)
        {
            m_items.Add(new FlagInfo(this) 
                {
                    Id = DbUtil.NewId(m_items, (i) => i.Id),
                    FlagName = ADDED_FLAG,
                    Active = true,
                    Count = 0 
                });
        }

        private void buttonRemove_Click(object sender, RoutedEventArgs e)
        {
            if (theListView.SelectedItem != null && theListView.SelectedItem is FlagInfo)
            {
                FlagInfo item = theListView.SelectedItem as FlagInfo;

                if (item.Id > 0)
                {
                    // Removing is only possible if there are no tracks related...
                    if (item.Count > 0)
                    {
                        MessageBox.Show(String.Format("Cannot remove {0}, there are {1} tracks associated", item.FlagName, item.Count),
                                "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                        return;
                    }

                    m_deletedItems.Add(item);
                }

                m_items.Remove(item);
            }
        }

        private void buttonRefresh_Click(object sender, RoutedEventArgs e)
        {
            Refresh();
        }

        public bool CommitIfNecessary()
        {
            if (!m_commitNecessary)
            {
                return false;
            }

            Db.Connection().ApplyUpdates
                (
                    m_items
                    , m_deletedItems
                    , (p) => p.Id < 0 // insert these
                    , (p) => p.Id > 0 // update these (== everything, even unchanged)
                );

            m_commitNecessary = false;
            //textBlockDebug.Text = "False after commit";

            return true;
        }

    }
}
